package luke.core.config;

import luke.core.logging.LogUtil;
import luke.core.utils.JsonUtils;  // 新增：导入JsonUtils

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * 应用程序数据管理类（单例模式）
 * 用于管理应用程序的配置数据，如更新设置、用户偏好等
 */
public class AppDataManager {
    private static final String APP_NAME = "RunBeats";
    private static final String CONFIG_FILE = "config.properties";
    // 添加新的常量定义
    private static final String LOGS_DIR = "logs";
    private static final String TEMP_DIR = "temp";
    private static final String SELECTED_FILES_DIR = "selected_files";  // 新增：已选择文件持久化目录
    private static final String CONFIG_COMMENT = "RunBeats Configuration";
    
    // 单例模式实例
    private static volatile AppDataManager instance;
    
    private Path appDataDir;
    private Path configFile;
    private Path logsDir;
    private Path tempDir;
    private Path selectedFilesDir;  // 新增：已选择文件目录路径
    private Properties properties;
    
    // 私有构造函数，防止外部实例化
    private AppDataManager() {
        initializeAppDataDirectory();//初始化应用程序数据目录
        properties = new Properties();//创建属性对象
        loadProperties();//加载属性
        // 确保配置文件存在，即使没有任何设置被保存
        ensureConfigFileExists();
        // 检查并清理日志文件
        checkAndCleanLogFiles();
        // 初始化抖音结尾音去除器
        initializeDouyinEndingSoundRemover();
    }
    
    /**
     * 确保配置文件存在，如果不存在则创建一个空的配置文件
     */
    private void ensureConfigFileExists() {
        if (!Files.exists(configFile)) {
            saveProperties(); // 创建空的配置文件
        }
    }
    
    /**
     * 检查配置文件是否存在
     * @return 配置文件是否存在
     */
    public boolean isConfigFileExists() {
        return Files.exists(configFile);
    }
    
    /**
     * 获取AppDataManager的单例实例
     * 使用双重检查锁定确保线程安全
     * @return AppDataManager的单例实例
     */
    public static AppDataManager getInstance() {
        if (instance == null) {
            synchronized (AppDataManager.class) {
                if (instance == null) {
                    instance = new AppDataManager();
                }
            }
        }
        return instance;
    }
    
    /**
     * 初始化应用程序数据目录
     */
    private void initializeAppDataDirectory() {
        String os = System.getProperty("os.name").toLowerCase();
        
        if (os.contains("win")) {
            // Windows系统使用AppData目录
            String appData = System.getenv("APPDATA");
            if (appData != null) {
                appDataDir = Paths.get(appData, APP_NAME);
            } else {
                // 如果获取不到APPDATA环境变量，则使用用户目录下的.runbeats文件夹
                appDataDir = Paths.get(System.getProperty("user.home"), "." + APP_NAME.toLowerCase());
            }
        } else {
            // 其他系统使用用户目录下的.runbeats文件夹
            appDataDir = Paths.get(System.getProperty("user.home"), "." + APP_NAME.toLowerCase());
        }
        
        configFile = appDataDir.resolve(CONFIG_FILE);
        logsDir = appDataDir.resolve(LOGS_DIR);
        tempDir = appDataDir.resolve(TEMP_DIR);
        selectedFilesDir = appDataDir.resolve(SELECTED_FILES_DIR);  // 新增：初始化已选择文件目录路径
        
        // 创建目录（如果不存在）
        try {
            Files.createDirectories(appDataDir);
            Files.createDirectories(logsDir);
            Files.createDirectories(tempDir);
            Files.createDirectories(selectedFilesDir);  // 新增：创建已选择文件目录
            
            // 清理临时目录中的所有内容
            cleanTempDirectory();
        } catch (IOException e) {
            LogUtil.error("AppDataManager", "创建应用程序数据目录失败", e.getMessage());
        }
    }
    
    /**
     * 清理临时目录中的所有内容
     * 在UI启动时确保临时目录是干净的
     */
    private void cleanTempDirectory() {
        try {
            if (Files.exists(tempDir)) {
                // 删除临时目录中的所有文件和子目录
                Files.walk(tempDir)
                    .sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.delete(path);
                        } catch (IOException e) {
                            LogUtil.error("AppDataManager", "删除临时文件失败", "路径: " + path + ", 错误: " + e.getMessage());
                        }
                    });
                
                // 重新创建临时目录
                Files.createDirectories(tempDir);
                LogUtil.info("AppDataManager", "临时目录清理", "临时目录已清理并重新创建: " + tempDir.toString());
            }
        } catch (IOException e) {
            LogUtil.error("AppDataManager", "清理临时目录失败", e.getMessage());
        }
    }
    
    /**
     * 加载配置属性
     */
    private void loadProperties() {
        if (Files.exists(configFile)) {
            try (InputStream input = Files.newInputStream(configFile)) {
                properties.load(input);
            } catch (IOException e) {
                LogUtil.error("AppDataManager", "加载配置文件失败", e.getMessage());
            }
        }
    }
    
    /**
     * 保存配置属性
     */
    public void saveProperties() {
        try {
            // 确保配置文件的父目录存在
            Files.createDirectories(configFile.getParent());
            try (OutputStream output = Files.newOutputStream(configFile)) {
                properties.store(output, CONFIG_COMMENT);
            }
        } catch (IOException e) {
            LogUtil.error("AppDataManager", "保存配置文件失败", e.getMessage());
        }
    }
    
    /**
     * 获取配置属性对象
     * @return Properties对象
     */
    public Properties getProperties() {
        return properties;
    }
    
    /**
     * 设置是否跳过版本更新提示
     * @param version 版本号
     * @param skip 是否跳过
     */
    public void setSkipVersionUpdate(String version, boolean skip) {
        properties.setProperty("skip_version_" + version, String.valueOf(skip));
        saveProperties();
    }
    
    /**
     * 检查是否跳过指定版本的更新提示
     * @param version 版本号
     * @return 是否跳过
     */
    public boolean isSkipVersionUpdate(String version) {
        return Boolean.parseBoolean(properties.getProperty("skip_version_" + version, "false"));
    }
    
    /**
     * 获取上次检查更新的时间戳
     * @return 时间戳（毫秒）
     */
    public long getLastUpdateCheckTime() {
        return Long.parseLong(properties.getProperty("last_update_check_time", "0"));
    }
    
    /**
     * 设置上次检查更新的时间戳
     * @param timestamp 时间戳（毫秒）
     */
    public void setLastUpdateCheckTime(long timestamp) {
        properties.setProperty("last_update_check_time", String.valueOf(timestamp));
        saveProperties();
    }
    
    /**
     * 设置捐赠状态
     * @param donated 是否已捐赠
     */
    public void setDonated(boolean donated) {
        properties.setProperty("donated", String.valueOf(donated));
        saveProperties();
    }
    
    /**
     * 检查是否已捐赠
     * @return 是否已捐赠
     */
    public boolean isDonated() {
        return Boolean.parseBoolean(properties.getProperty("donated", "false"));
    }
    
    /**
     * 增加生成次数计数器
     * @return 当前生成次数
     */
    public int incrementGenerationCount() {
        int count = getGenerationCount();
        count++;
        properties.setProperty("generation_count", String.valueOf(count));
        saveProperties();
        return count;
    }
    
    /**
     * 获取生成次数计数器
     * @return 生成次数
     */
    public int getGenerationCount() {
        return Integer.parseInt(properties.getProperty("generation_count", "0"));
    }
    
    /**
     * 设置音量设置
     * @param volume 音量值(0.0-1.0)
     */
    public void setVolume(float volume) {
        properties.setProperty("volume", String.valueOf(volume));
        saveProperties();
    }
    
    /**
     * 获取音量设置
     * @return 音量值(0.0-1.0)，默认为1.0
     */
    public float getVolume() {
        String volumeStr = properties.getProperty("volume", "1.0");
        try {
            return Float.parseFloat(volumeStr);
        } catch (NumberFormatException e) {
            return 1.0f; // 默认音量
        }
    }
    
    /**
     * 设置节拍音量设置
     * @param beatVolume 节拍音量值(0.0-1.0)
     */
    public void setBeatVolume(float beatVolume) {
        properties.setProperty("beat_volume", String.valueOf(beatVolume));
        saveProperties();
    }
    
    /**
     * 获取节拍音量设置
     * @return 节拍音量值(0.0-1.0)，默认为1.0
     */
    public float getBeatVolume() {
        String beatVolumeStr = properties.getProperty("beat_volume", "1.0");
        try {
            return Float.parseFloat(beatVolumeStr);
        } catch (NumberFormatException e) {
            return 1.0f; // 默认节拍音量
        }
    }
    
    /**
     * 设置节拍音效类型
     * @param beatSoundType 节拍音效类型(0-3)
     */
    public void setBeatSoundType(int beatSoundType) {
        properties.setProperty("beat_sound_type", String.valueOf(beatSoundType));
        saveProperties();
    }
    
    /**
     * 获取节拍音效类型
     * @return 节拍音效类型(0-3)，默认为0
     */
    public int getBeatSoundType() {
        String beatSoundTypeStr = properties.getProperty("beat_sound_type", "0");
        try {
            return Integer.parseInt(beatSoundTypeStr);
        } catch (NumberFormatException e) {
            return 0; // 默认节拍音效类型
        }
    }
    
    /**
     * 设置背景音量设置
     * @param backgroundVolume 背景音量值(0.0-1.0)
     */
    public void setBackgroundVolume(float backgroundVolume) {
        properties.setProperty("background_volume", String.valueOf(backgroundVolume));
        saveProperties();
    }
    
    /**
     * 获取背景音量设置
     * @return 背景音量值(0.0-1.0)，默认为1.0
     */
    public float getBackgroundVolume() {
        String backgroundVolumeStr = properties.getProperty("background_volume", "1.0");
        try {
            return Float.parseFloat(backgroundVolumeStr);
        } catch (NumberFormatException e) {
            return 1.0f; // 默认背景音量
        }
    }
    
    /**
     * 设置视频分辨率偏好设置
     * @param resolution 分辨率（如"1080p"）
     * @param isLandscape 是否为横屏模式
     */
    public void setVideoResolutionPreference(String resolution, boolean isLandscape) {
        properties.setProperty("video_resolution", resolution);
        properties.setProperty("video_landscape", String.valueOf(isLandscape));
        saveProperties();
    }
    
    /**
     * 获取视频分辨率偏好设置
     * @return 包含分辨率和横屏设置的数组，[0]为分辨率，[1]为横屏设置
     */
    public String[] getVideoResolutionPreference() {
        String resolution = properties.getProperty("video_resolution", "1080p");
        String isLandscape = properties.getProperty("video_landscape", "true");
        return new String[]{resolution, isLandscape};
    }
    
    /**
     * 设置视频样式偏好设置
     * @param style 视频样式（"slideshow"或"spectrum"）
     */
    public void setVideoStylePreference(String style) {
        properties.setProperty("video_style", style);
        saveProperties();
    }
    
    /**
     * 获取视频样式偏好设置
     * @return 视频样式（"slideshow"或"spectrum"），默认为"slideshow"
     */
    public String getVideoStylePreference() {
        return properties.getProperty("video_style", "slideshow");
    }
    
    /**
     * 获取应用程序数据目录路径
     * @return 应用程序数据目录路径
     */
    public Path getAppDataDirectory() {
        return appDataDir;
    }
    
    /**
     * 获取日志目录路径
     * @return 日志目录路径
     */
    public Path getLogsDirectory() {
        return logsDir;
    }
    
    /**
     * 获取临时目录路径
     * @return 临时目录路径
     */
    public Path getTempDirectory() {
        return tempDir;
    }
    
    /**
     * 获取系统临时目录路径（跨平台）
     * @return 系统临时目录路径
     */
    public Path getSystemTempDirectory() {
        return Paths.get(System.getProperty("java.io.tmpdir"), APP_NAME);
    }
    
    /**
     * 获取已选择文件持久化目录路径
     * 
     * @return 已选择文件目录路径
     */
    public Path getSelectedFilesDirectory() {
        return selectedFilesDir;
    }
    
    /**
     * 保存已选择文件列表到持久化文件
     * 
     * @param selectedFiles 已选择的文件集合
     * @param directoryPath 当前目录路径（用作文件名）
     */
    public void saveSelectedFiles(List<File> selectedFiles, String directoryPath) {
        try {
            // 创建目录的哈希值作为文件名，避免特殊字符问题
            String fileName = "selected_files_" + directoryPath.hashCode() + ".json";
            Path filePath = selectedFilesDir.resolve(fileName);
            
            // 将File对象转换为路径字符串列表进行序列化
            List<String> filePaths = new ArrayList<>();
            for (File file : selectedFiles) {
                filePaths.add(file.getAbsolutePath());
            }
            
            // 使用JsonUtils将文件路径列表写入JSON文件
            JsonUtils.writeToJson(filePaths, filePath.toString());
            LogUtil.info("AppDataManager", "已选择文件保存", "已保存 " + selectedFiles.size() + " 个文件到 " + filePath.toString());
        } catch (Exception e) {
            LogUtil.error("AppDataManager", "保存已选择文件失败", e.getMessage());
        }
    }
    
    /**
     * 从持久化文件恢复已选择文件列表
     * 
     * @param directoryPath 当前目录路径（用作文件名）
     * @param availableFiles 当前目录中可用的文件列表
     * @return 恢复的已选择文件集合
     */
   public List<File> loadSelectedFiles(String directoryPath, List<File> availableFiles) {
    List<File> selectedFiles = new ArrayList<>();  // 改为ArrayList以保持顺序
    try {
        // 创建目录的哈希值作为文件名，与保存时保持一致
        String fileName = "selected_files_" + directoryPath.hashCode() + ".json";
        Path filePath = selectedFilesDir.resolve(fileName);

        // 检查持久化文件是否存在
        if (Files.exists(filePath)) {
            // 从JSON文件读取文件路径列表
            List<String> filePaths = JsonUtils.readFromJson(filePath.toString(), List.class);

            // 将路径字符串转换为File对象，并检查是否在当前目录中可用
            Set<String> availableFilePaths = new HashSet<>();
            for (File file : availableFiles) {
                availableFilePaths.add(file.getAbsolutePath());
            }

            for (String path : filePaths) {
                File file = new File(path);
                // 只有当文件在当前目录中存在时才添加到已选择集合中
                if (availableFilePaths.contains(path)) {
                    selectedFiles.add(file);  // 保持文件添加顺序
                }
            }

            LogUtil.info("AppDataManager", "已选择文件恢复", "已恢复 " + selectedFiles.size() + " 个文件从 " + filePath.toString());
        }
    } catch (Exception e) {
        LogUtil.error("AppDataManager", "恢复已选择文件失败", e.getMessage());
    }
    return selectedFiles;
}

    
    /**
     * 初始化抖音结尾音去除器
     * 在应用启动时将dy.wav复制到相关文件夹下
     */
    private void initializeDouyinEndingSoundRemover() {
        try {
            // 直接复制dy.wav文件到应用程序数据目录
            Path appDataDir = getAppDataDirectory();
            Path targetDir = appDataDir.resolve("audio");
            
            // 创建目录（如果不存在）
            Files.createDirectories(targetDir);
            
            // 目标文件路径
            Path targetFile = targetDir.resolve("dy.wav");
            
            // 检查源文件是否存在
            File sourceFile = new File("src/main/resources/auido/dy.wav");
            if (sourceFile.exists()) {
                // 复制文件到目标位置
                Files.copy(sourceFile.toPath(), targetFile, StandardCopyOption.REPLACE_EXISTING);
                LogUtil.info("AppDataManager", "初始化抖音结尾音去除器", "dy.wav文件已复制到: " + targetFile.toString());
            } else {
                LogUtil.error("AppDataManager", "初始化抖音结尾音去除器", "源文件不存在: " + sourceFile.getAbsolutePath());
            }
        } catch (Exception e) {
            LogUtil.error("AppDataManager", "初始化抖音结尾音去除器", "复制dy.wav文件时发生错误: " + e.getMessage());
        }
    }

    /**
     * 检查并清理日志文件
     * 如果日志文件大于100MB或最后修改时间超过1天，则删除日志文件
     */
    public void checkAndCleanLogFiles() {
        try {
            // 从LogUtil获取日志文件名，避免硬编码
            Path logFile = logsDir.resolve(LogUtil.getLogFileName());
            if (Files.exists(logFile)) {
                // 检查文件大小
                long fileSize = Files.size(logFile);
                long maxSize = 100 * 1024 * 1024; // 100MB in bytes
                
                // 检查文件修改时间
                java.nio.file.attribute.FileTime lastModified = Files.getLastModifiedTime(logFile);
                long currentTime = System.currentTimeMillis();
                long oneDayInMillis = 24 * 60 * 60 * 1000L; // 1 day in milliseconds
                long fileTime = lastModified.toMillis();
                
                // 如果文件大于100MB或最后修改时间超过1天，则删除文件
                if (fileSize > maxSize || (currentTime - fileTime) > oneDayInMillis) {
                    Files.delete(logFile);
                    LogUtil.info("AppDataManager", "日志文件清理", 
                        String.format("日志文件已删除 - 大小: %d bytes, 最后修改时间: %tc", fileSize, fileTime));
                }
            }
        } catch (IOException e) {
            LogUtil.error("AppDataManager", "日志文件检查失败", e.getMessage());
        }
    }
    
    /**
     * 获取上次显示更新内容的版本号
     * @return 版本号
     */
    public String getLastShownUpdateVersion() {
        return properties.getProperty("last_shown_update_version", "");
    }
    
    /**
     * 设置上次显示更新内容的版本号
     * @param version 版本号
     */
    public void setLastShownUpdateVersion(String version) {
        properties.setProperty("last_shown_update_version", version);
        saveProperties();
    }
}